package com.stark.core.boot.config;

import java.net.URI;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;

import com.stark.core.boot.properties.SwaggerProperties;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * swagger 配置。
 * @author Ben
 */
@Configuration
@ConditionalOnClass(name = "springfox.documentation.oas.annotations.EnableOpenApi")
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfig {
	
	@Configuration
	@ConditionalOnClass(name = "springfox.documentation.oas.annotations.EnableOpenApi")
	@ConditionalOnProperty(prefix = "swagger.oauth2", name = "enabled", havingValue = "false", matchIfMissing = true)
	protected static class SwaggerConfig {
		
		@Autowired
		private SwaggerProperties swaggerProperties;
		
		@Bean
		public Docket createRestApi() {
			return new Docket(DocumentationType.SWAGGER_2)
					.apiInfo(apiInfo(swaggerProperties))
					.select()
					.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
					.paths(PathSelectors.any())
					.build();
		}
		
	}
	
	@Configuration
	@ConditionalOnClass(name = "springfox.documentation.oas.annotations.EnableOpenApi")
	@ConditionalOnWebApplication(type = Type.SERVLET)
	protected static class SwaggerWebMvcConfig {
		
		@Autowired
		private SwaggerProperties swaggerProperties;
		
		@Bean
		public WebMvcConfigurer swaggerWebMvcConfigurer() {
			return new WebMvcConfigurer() {
				
				@Override
				public void addViewControllers(ViewControllerRegistry registry) {
					if (swaggerProperties.isIndexRedirect()) {
						registry.addRedirectViewController("/", "/swagger-ui/index.html");
						registry.addRedirectViewController("/index", "/swagger-ui/index.html");
					}
				}
			};
		}
		
	}
	
	@Configuration
	@ConditionalOnClass(name = "springfox.documentation.oas.annotations.EnableOpenApi")
	@ConditionalOnWebApplication(type = Type.REACTIVE)
	protected static class SwaggerWebFluxConfig {
		
		@Bean
		@ConditionalOnProperty(prefix = "swagger", name = "index-redirect", havingValue = "true")
		public RouterFunction<ServerResponse> swaggerIndexRouter() {
			return RouterFunctions.route()
					.GET("/", request -> ServerResponse.temporaryRedirect(URI.create("/swagger-ui/index.html")).build())
					.GET("/index", request -> ServerResponse.temporaryRedirect(URI.create("/swagger-ui/index.html")).build())
					.build();
		}

	}
	
	private static ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
		return new ApiInfoBuilder()
				.title(swaggerProperties.getTitle())
				.description(swaggerProperties.getDescription())
				.version(swaggerProperties.getVersion())
				.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
				.contact(contact(swaggerProperties))
				.license(swaggerProperties.getLicense())
				.licenseUrl(swaggerProperties.getLicenseUrl())
				.build();
	}
	
	private static Contact contact(SwaggerProperties swaggerProperties) {
		return new Contact(
				swaggerProperties.getContactName(),
				swaggerProperties.getContactUrl(),
				swaggerProperties.getContactEmail());
	}
	
}
